﻿using UnityEngine;
using System.Collections;

public class PlayerStateListener : MonoBehaviour {
	//Propriedades
	public float playerWalkSpeed = 3f;
	public float playerJumpForceVertical = 500f;
	public float playerJumpForceHorizontal = 10f;
	private PlayerStateController.playerState previousState = PlayerStateController.playerState.idle;
	public PlayerStateController.playerState currentState = PlayerStateController.playerState.idle;
	private bool playerHasLanded = true;
	private Animator playerAnimator = null;
	private PlayerStateController.playerForm currentForm = PlayerStateController.playerForm.humanForm;

	//Prefab Objects
	public GameObject attackEffect = null;
	public Transform attackSpawnTransform;

	//Metodos
	private void onStateCycle()
	{
		Vector3 localScale = transform.localScale;
		switch (currentState) 
		{
			case PlayerStateController.playerState.idle:
			break;

			case PlayerStateController.playerState.left:
				if(previousState.Equals(PlayerStateController.playerState.jumping)||previousState.Equals(PlayerStateController.playerState.jumpMoving))
				{
					onStateChange(PlayerStateController.playerState.jumpMoving);
				}
				transform.Translate(new Vector3((playerWalkSpeed * -1.0f) * Time.deltaTime, 0.0f, 0.0f));				
				if(localScale.x > 0.0f)
				{
					if(CanTurn())
						localScale.x *= -1.0f;
					transform.localScale  = localScale;
				}
			break;

			case PlayerStateController.playerState.right:
				if(previousState.Equals(PlayerStateController.playerState.jumping)||previousState.Equals(PlayerStateController.playerState.jumpMoving))
				{
					onStateChange(PlayerStateController.playerState.jumpMoving);
				}
				transform.Translate(new Vector3(playerWalkSpeed * Time.deltaTime, 0.0f, 0.0f));
				
				if(localScale.x < 0.0f)
				{
					if(CanTurn())
						localScale.x *= -1.0f;
					transform.localScale = localScale;              
				}				
			break;

			case PlayerStateController.playerState.jumpMoving:
				if (previousState.Equals(PlayerStateController.playerState.left))
				{
					transform.Translate(new Vector3((playerWalkSpeed * -1.0f) * Time.deltaTime, 0.0f, 0.0f));				
					if(localScale.x > 0.0f)
					{
						localScale.x *= -1.0f;
						transform.localScale  = localScale;
					}
				}
				else
				{
					transform.Translate(new Vector3(playerWalkSpeed * Time.deltaTime, 0.0f, 0.0f));
					
					if(localScale.x < 0.0f)
					{
						localScale.x *= -1.0f;
						transform.localScale = localScale;              
					}
				}
			break;

			case PlayerStateController.playerState.falling:
			break;

			case PlayerStateController.playerState.jumping:
			break;

			case PlayerStateController.playerState.landing:
			break;

			case PlayerStateController.playerState.attacking:
			break;

			case PlayerStateController.playerState.casting:
			break;

			case PlayerStateController.playerState.defending:
			break;

			case PlayerStateController.playerState.lDashing:				
			break;

			case PlayerStateController.playerState.rDashing:
			break;

			case PlayerStateController.playerState.waterForm:
			break;

			case PlayerStateController.playerState.flyForm:
			break;

			case PlayerStateController.playerState.dead:
			break;			 
		}
	}

	public void onStateChange(PlayerStateController.playerState newState)
	{
		if(newState == currentState)
			return;
		
		if (CheckIfAbortOnStateCondition(newState))
			return;
		
		if(!CheckForValidStatePair(newState))
			return;
		
		switch (newState) 
		{
			case PlayerStateController.playerState.idle:
				playerAnimator.SetBool ("Walking", false);
			break;
			
			case PlayerStateController.playerState.left:				
				playerAnimator.SetBool ("Walking", true);
			break;
			
			case PlayerStateController.playerState.right:				
				playerAnimator.SetBool ("Walking", true);
			break;						

			case PlayerStateController.playerState.jumping:
				if(playerHasLanded)
				{
					float jumpDirection = 0.0f;
					if(currentState == PlayerStateController.playerState.left)
					{
						jumpDirection = -1.0f;
					}					
					else if(currentState == PlayerStateController.playerState.right)
					{
						jumpDirection = 1.0f;
					}
					
					//pula de fato * playerJumpForceHorizontal
					rigidbody2D.AddForce(new Vector2(jumpDirection  ,playerJumpForceVertical));
					
					playerHasLanded = false;
					PlayerStateController.stateDelayTimer[(int)PlayerStateController.playerState.jumping] = 0f;
				}
			break;

			case PlayerStateController.playerState.jumpMoving:				
			break;

			case PlayerStateController.playerState.attacking: 
				GameObject newAttack = (GameObject)Instantiate(attackEffect);
				playerAnimator.Play("Player_Attack");
				
				newAttack.transform.position = attackSpawnTransform.position;
				
				PlayerAttackController attackController = newAttack.GetComponent<PlayerAttackController>();
				
				attackController.playerObject = gameObject;
				attackController.SpawnPoint = attackSpawnTransform;
				attackController.LaunchAttack();
				onStateChange(currentState); 				
				PlayerStateController.stateDelayTimer[(int)PlayerStateController.playerState.attacking] = Time.time + 0.6f;	
			break;

			case PlayerStateController.playerState.landing:
				playerHasLanded = true;
				PlayerStateController.stateDelayTimer[(int)PlayerStateController.playerState.jumping] = Time.time + 0.1f;
			break;	

			case PlayerStateController.playerState.falling:
				PlayerStateController.stateDelayTimer[(int)PlayerStateController.playerState.jumping] = 0f;
			break;

			case PlayerStateController.playerState.lDashing:
				rigidbody2D.AddForce(new Vector2(-300,0));
				PlayerStateController.stateDelayTimer[(int)PlayerStateController.playerState.lDashing] = Time.time + 1.5f;
			break;

			case PlayerStateController.playerState.rDashing:
				rigidbody2D.AddForce(new Vector2(300,0));
				PlayerStateController.stateDelayTimer[(int)PlayerStateController.playerState.rDashing] = Time.time + 1.5f;
			break;

			case PlayerStateController.playerState.dead:				
			break;

			case PlayerStateController.playerState.defending:				
			break;

			case PlayerStateController.playerState.waterForm:	
				if(currentForm.Equals(PlayerStateController.playerForm.waterForm))
				{
					currentForm = PlayerStateController.playerForm.humanForm;
					playerAnimator.SetBool ("WaterForm", false);					
				}
				else
				{
					currentForm = PlayerStateController.playerForm.waterForm;
					playerAnimator.SetBool ("WaterForm", true);
				}
				PlayerStateController.stateDelayTimer [(int)PlayerStateController.playerState.waterForm] = Time.time + 3.0f;
			break;

			case PlayerStateController.playerState.flyForm:
				if(currentForm.Equals(PlayerStateController.playerForm.flyForm))
				{
					currentForm = PlayerStateController.playerForm.humanForm;
					playerAnimator.SetBool ("FlyForm", false);
					rigidbody2D.gravityScale = 2;
				}
				else
				{
					currentForm = PlayerStateController.playerForm.flyForm;
					playerAnimator.SetBool ("FlyForm", true);
					rigidbody2D.gravityScale = 0;
				}
				PlayerStateController.stateDelayTimer [(int)PlayerStateController.playerState.flyForm] = Time.time + 3.0f;
			break;
					
		}		
		// And finally, assign the new state to the player object
		previousState = currentState;
		currentState = newState;
	}

	private bool CheckForValidStatePair(PlayerStateController.playerState newState)
	{
		bool returnVal = false;
		
		switch(currentState)
		{
			case PlayerStateController.playerState.idle:
				returnVal = true;
			break;
			
			case PlayerStateController.playerState.left:
				returnVal = true;
			break;
			
			case PlayerStateController.playerState.right:
				returnVal = true;
			break;	
			
			//os eventos no if sao os que podem substituir o evento do case
			case PlayerStateController.playerState.jumping:
				if(newState == PlayerStateController.playerState.landing ||
				   newState == PlayerStateController.playerState.dead ||
				   newState == PlayerStateController.playerState.left ||
				   newState == PlayerStateController.playerState.right ||
			   	   newState == PlayerStateController.playerState.attacking ||
				   newState == PlayerStateController.playerState.rDashing ||
				   newState == PlayerStateController.playerState.lDashing)
					returnVal = true;
				else
					returnVal = false;
			break;			

			case PlayerStateController.playerState.landing:
				if(newState == PlayerStateController.playerState.left ||
				   newState == PlayerStateController.playerState.right ||
				   newState == PlayerStateController.playerState.idle)
					returnVal = true;
				else
					returnVal = false;
			break;

			case PlayerStateController.playerState.jumpMoving:
				if(newState == PlayerStateController.playerState.left ||
				   newState == PlayerStateController.playerState.right ||
				   newState == PlayerStateController.playerState.landing)
					returnVal = true;
				else
					returnVal = false;
			break;		

			case PlayerStateController.playerState.falling:  				
				if(newState == PlayerStateController.playerState.landing ||
				   newState == PlayerStateController.playerState.left ||
				   newState == PlayerStateController.playerState.right)
					returnVal = true;
				else
					returnVal = false;
			break;  

			case PlayerStateController.playerState.attacking:				
				returnVal = true;
			break;

			case PlayerStateController.playerState.defending:				
				returnVal = true;
			break;

			case PlayerStateController.playerState.dead:				
				returnVal = true;
			break;

			case PlayerStateController.playerState.lDashing:				
				returnVal = true;
			break;

			case PlayerStateController.playerState.rDashing:				
				returnVal = true;
			break;

			case PlayerStateController.playerState.casting:				
				returnVal = true;
			break;

			case PlayerStateController.playerState.waterForm:				
				returnVal = true;
			break;

			case PlayerStateController.playerState.flyForm:				
				returnVal = true;
			break;
		}
		return returnVal;
	}

	private bool CheckIfAbortOnStateCondition(PlayerStateController.playerState newState)
	{
		bool returnVal = false;
		switch (newState) 
		{
			case PlayerStateController.playerState.idle:
			break;
			
			case PlayerStateController.playerState.left:
			break;
			
			case PlayerStateController.playerState.right:
			break;
			
			case PlayerStateController.playerState.jumping:
				float nextAllowedJumpTime = PlayerStateController.stateDelayTimer[(int)PlayerStateController.playerState.jumping];
				if(nextAllowedJumpTime == 0.0f || nextAllowedJumpTime > Time.time)
					returnVal = true;
			break;
						
			case PlayerStateController.playerState.landing:
			break;
						
			case PlayerStateController.playerState.dead:
			break;

			case PlayerStateController.playerState.attacking:
				if(PlayerStateController.stateDelayTimer[ (int)PlayerStateController.playerState.attacking] > Time.time)
					returnVal = true;
			break;

			case PlayerStateController.playerState.lDashing:
				if(PlayerStateController.stateDelayTimer[ (int)PlayerStateController.playerState.lDashing] > Time.time)
					returnVal = true;
			break;

			case PlayerStateController.playerState.falling:
			break;

			case PlayerStateController.playerState.jumpMoving:
			break;

			case PlayerStateController.playerState.defending:
			break;

			case PlayerStateController.playerState.rDashing:
				if(PlayerStateController.stateDelayTimer[ (int)PlayerStateController.playerState.rDashing] > Time.time)
					returnVal = true;
			break;

			case PlayerStateController.playerState.casting:
			break;

			case PlayerStateController.playerState.waterForm:
				if(PlayerStateController.stateDelayTimer[ (int)PlayerStateController.playerState.waterForm] > Time.time)
					returnVal = true;
			break;

			case PlayerStateController.playerState.flyForm:
				if(PlayerStateController.stateDelayTimer[ (int)PlayerStateController.playerState.flyForm] > Time.time)
					returnVal = true;
			break;
		}
		//true means abort
		return returnVal;
	}			

	//Engine
	void LateUpdate()
	{
		onStateCycle();
	}
	
	void OnEnable()
	{
		PlayerStateController.onStateChange += onStateChange;
	}

	void OnDisable()
	{
		PlayerStateController.onStateChange -= onStateChange;
	}

	void Start()
	{
		playerAnimator = GetComponent<Animator>();
		//adicionando valores de delay para os estados
		PlayerStateController.stateDelayTimer [(int)PlayerStateController.playerState.jumping] = 1.0f;
		PlayerStateController.stateDelayTimer [(int)PlayerStateController.playerState.attacking] = 0.6f;
		PlayerStateController.stateDelayTimer [(int)PlayerStateController.playerState.lDashing] = 0.0f;
		PlayerStateController.stateDelayTimer [(int)PlayerStateController.playerState.rDashing] = 0.0f;
		PlayerStateController.stateDelayTimer [(int)PlayerStateController.playerState.flyForm] = 0.0f;
		PlayerStateController.stateDelayTimer [(int)PlayerStateController.playerState.waterForm] = 0.0f;
	}	

	private bool CanTurn()
	{
		bool AttackDelayOver = PlayerStateController.stateDelayTimer[(int)PlayerStateController.playerState.attacking] < Time.time;
		return AttackDelayOver;
	}

}
